// #include <mln/core/image/image2d.hh>
// #include <mln/make/image.hh>
// #include <mln/debug/println.hh>
// #include <mln/io/pbm/load.hh>
// #include <mln/io/pbm/save.hh>
// #include <mln/logical/not.hh>
// #include <mln/labeling/blobs.hh>
//// #include <mln/value/all.hh>
// #include <mln/core/neighb.hh>
#include <mln/all.hh>
#include <iostream>
#include <list>

using namespace mln;
using namespace mln::value;
using namespace mln::morpho;


// Fonction qui detecte les contours des zones d'une image.
// Pour l'instant, aucune differentiation n'est faite par rapport
// aux composante connexes..

template <typename I, typename N>
void
get_limits (I& ima, std::list<point2d>& list)
{
  mln_piter (I) p(ima.domain());
  mln_niter (N) n(c8 (), p);
  bool cont;

  for_all (p)
  {
    cont = false;
    if (ima(p) == literal::zero)
      {
	for_all (n)
	{
	  if (ima(n) == literal::one)
	    cont = true;
	}
	if (cont == true)
	  list.push_back (p);
      }
  }
}

// Fonction qui realise une ouverture.
// Deja presente dans milena, mais je n'etais pas sur de comment l'utiliser.

template <typename I>
I&
my_closing(I& ima)
{
  bool b[81] =	{ 0, 0, 0, 0, 1, 0, 0, 0, 0,
		  0, 0, 0, 1, 1, 1, 0, 0, 0,
		  0, 0, 1, 1, 1, 1, 1, 0, 0,
		  0, 1, 1, 1, 1, 1, 1, 1, 0,
		  1, 1, 1, 1, 1, 1, 1, 1, 1,
		  0, 1, 1, 1, 1, 1, 1, 1, 0,
		  0, 0, 1, 1, 1, 1, 1, 0, 0,
		  0, 0, 0, 1, 1, 1, 0, 0, 0,
		  0, 0, 0, 0, 1, 0, 0, 0, 0 };

  window2d win = convert::to<window2d>(b);

  ima = dilation (ima, win);
  ima = erosion (ima, win);

  return ima;
}

template <typename I>
Image<I>&
get_labels (Image<I>& ima)
{
  label_16 nlabels;
  unsigned max = 0;
  unsigned index = 0;
  std::list<unsigned> label_numbers;
  std::list<unsigned>::const_iterator it;
  std::vector<label_16> label_array;

  mln_ch_value(I, label_16) lbl = labeling::blobs(ima, c4(), nlabels);

  util::array<unsigned> count = labeling::compute(accu::meta::math::count (),
						  lbl, nlabels);

  for (unsigned i = 1; i <= nlabels; ++i)
    if (count[i] > 10000u)
      label_numbers.push_back (i);

  for (it = label_numbers.begin (); it != label_numbers.end (); ++it)
    {
      (mln_VAR(label_array.push_front (), lbl | (pw::value(lbl) == pw::cst(index))));
      
      data::fill (ima, literal::one);
      data::fill((ima | label_array[0].domain()).rw(), literal::zero);
      
      lbl = labeling::blobs(ima, c4(), nlabels);
      count = labeling::compute(accu::meta::math::count (),
				lbl, nlabels);
      
      max = 0;
      for (unsigned i = 1; i <= nlabels; ++i)
	if (count[i] > max)
	  {
	    max = count[i];
	    index = i;
	  }

      (mln_VAR(label_array.push_front (), lbl | (pw::value(lbl) == pw::cst(index))));
      
      data::fill (ima, literal::one);
      data::fill((ima | label_array[0].domain()).rw(), literal::zero);
    }


  return ima;
}


template <typename I>
void
make_ima_from_points (I& ima, std::list<point2d>& list)
{
  typename std::list<point2d>::const_iterator it;

  data::fill (ima, literal::zero);
  for (it = list.begin (); it != list.end (); ++it)
    ima(*it) = literal::one;
}


int
main (int argc, char** argv)
{
  image2d<bool> ima;
  std::list <point2d> list;

  trace::quiet = false;
  io::pbm::load (ima, argv[1]);

  ima = my_closing (ima);

  ima = duplicate (get_labels (ima));

  //  get_limits<image2d<bool>, neighb2d> (ima, list);

  //  make_ima_from_points (ima, list);

  io::pbm::save(ima, "mp00255c.out.pbm");
  return 0;
}
